{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "a3c.ipynb",
      "provenance": [],
      "collapsed_sections": [],
      "authorship_tag": "ABX9TyPABBzUO8+ILyBRYxd7+Fw2",
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/letianzj/QuantResearch/blob/master/ml/a3c.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JlNkxcEuDTVn",
        "colab_type": "text"
      },
      "source": [
        "## A3C CartPole\n",
        "\n",
        "Use A3C to solve CartPole game.\n",
        "\n",
        "[OpenAI Gym CartPole](https://gym.openai.com/envs/CartPole-v0/) has four states, cart position, cart speed, pole angle, and pole speed. The actions are either going left or right. The objective is to keep pole from falling. Every move that doesn't lead to a fall gets reward 1.\n",
        "\n",
        "A3C (Asynchronous Advantage Actor-Critic) is the asynchronous version of A2C proposed by DeepMind. Each worker pulls model parameters from global network and then feed updated parameters back after local training. Actor learns policy network while critic learns value network, and\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "\\frac{\\partial J}{\\partial \\theta}&=E_{\\tau \\sim \\pi_{\\theta}(\\tau)} \\left[\\sum_{t=1}^{T} \\frac{\\partial}{\\partial\\theta}log \\left( \\pi_{\\theta}(a_t|s_t) \\right) A^{\\pi}(s_t, a_t)  \\right] \\\\\n",
        "A^{\\pi}(s_t,a_t) &= R(\\tau) - V^{\\pi}(s_t)\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "The losses care computed respectively as,\n",
        "\n",
        "$$\n",
        "\\begin{aligned}\n",
        "ValueLoss &= \\sum (R - V(s))^2 \\\\\n",
        "PolicyLoss &= -log(\\pi(s))*A(s)\n",
        "\\end{aligned}\n",
        "$$\n",
        "\n",
        "This notebook follows closely [here](https://blog.tensorflow.org/2018/07/deep-reinforcement-learning-keras-eager-execution.html) and [here](https://github.com/dragen1860/Deep-Learning-with-TensorFlow-book/blob/master/ch14-%E5%BC%BA%E5%8C%96%E5%AD%A6%E4%B9%A0/a3c_tf_cartpole.py).\n",
        "\n",
        "__Reference__\n",
        "* Sutton, Richard S., and Andrew G. Barto. Reinforcement learning: An introduction. MIT press, 2018.\n",
        "* [RL by David Silver](https://www.davidsilver.uk/teaching/)\n",
        "* [OpenAI Spinning Up](https://spinningup.openai.com/en/latest/)\n",
        "* [OpenAI Baseline](https://github.com/openai/baselines/tree/master/baselines/a2c)\n",
        "* [Deep Learning with TensorFlow](https://github.com/dragen1860/Deep-Learning-with-TensorFlow-book)\n",
        "* [Tensorflow Blog](https://blog.tensorflow.org/2018/07/deep-reinforcement-learning-keras-eager-execution.html)"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "0lOf7OSWHOvv",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import os\n",
        "import gym\n",
        "import numpy as np\n",
        "import multiprocessing\n",
        "import threading\n",
        "from queue import Queue\n",
        "import matplotlib.pyplot as plt\n",
        "import tensorflow as tf\n",
        "from tensorflow import keras\n",
        "\n",
        "tf.random.set_seed(1231)\n",
        "np.random.seed(1231)"
      ],
      "execution_count": 84,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "DBkjnGo3gQVJ",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "class ActorCritic(keras.Model):\n",
        "    def __init__(self, state_size, action_size):\n",
        "        super(ActorCritic, self).__init__()\n",
        "        self.state_size = state_size\n",
        "        self.action_size = action_size\n",
        "        # Actor\n",
        "        self.dense1 = keras.layers.Dense(128, activation='relu')\n",
        "        self.policy_logits = keras.layers.Dense(action_size)\n",
        "        # Critic\n",
        "        self.dense2 = keras.layers.Dense(128, activation='relu')\n",
        "        self.values = keras.layers.Dense(1)\n",
        "\n",
        "    def call(self, inputs):\n",
        "        # input s, output Pi(a|s), shape=(b, 2)\n",
        "        x = self.dense1(inputs)\n",
        "        logits = self.policy_logits(x)     \n",
        "        # input s, output v(s), shape=(b,)\n",
        "        v = self.dense2(inputs)\n",
        "        values = self.values(v)             \n",
        "        return logits, values"
      ],
      "execution_count": 85,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Q9Qlv_LOg-CB",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "class Memory:\n",
        "    def __init__(self):\n",
        "        self.states = []\n",
        "        self.actions = []\n",
        "        self.rewards = []\n",
        "\n",
        "    def store(self, state, action, reward):\n",
        "        self.states.append(state)\n",
        "        self.actions.append(action)\n",
        "        self.rewards.append(reward)\n",
        "\n",
        "    def clear(self):\n",
        "        self.states = []\n",
        "        self.actions = []\n",
        "        self.rewards = []"
      ],
      "execution_count": 86,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "JHQetx3pgEd2",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "class Worker(threading.Thread): \n",
        "    def __init__(self,  server, opt, result_queue, idx):\n",
        "        super(Worker, self).__init__()\n",
        "        self.result_queue = result_queue    # shared queue to track results\n",
        "        self.server = server       # global network\n",
        "        self.opt = opt             # global optimizer\n",
        "        self.client = ActorCritic(4, 2)      # local agent\n",
        "        self.worker_idx = idx     # worker id\n",
        "        self.env = gym.make('CartPole-v1').unwrapped\n",
        "        self.ep_loss = 0.0\n",
        "\n",
        "    def run(self): \n",
        "        mem = Memory() # local memory queue for local experiences\n",
        "        for epi_counter in range(500): # run one episode\n",
        "            current_state = self.env.reset()\n",
        "            mem.clear()\n",
        "            ep_reward = 0.\n",
        "            ep_steps = 0  \n",
        "            done = False\n",
        "            while not done:\n",
        "                # (1, 4) ==> (1, 2), logits of Pi(a|s)\n",
        "                logits, _ = self.client(tf.constant(current_state.reshape([1,-1]), dtype=tf.float32))\n",
        "                probs = tf.nn.softmax(logits)          # logits ==> prob\n",
        "                # random action according to \\pi\n",
        "                action = np.random.choice(np.arange(2), p=probs.numpy()[0])\n",
        "                new_state, reward, done, _ = self.env.step(action)\n",
        "                ep_reward += reward\n",
        "                mem.store(current_state, action, reward) # save experience\n",
        "                ep_steps += 1\n",
        "                current_state = new_state\n",
        "\n",
        "                if ep_steps >= 500 or done: # maximum 500 steps; or finished one episode\n",
        "                    # optimize total loss\n",
        "                    with tf.GradientTape() as tape:\n",
        "                        total_loss = self.compute_loss(done, new_state, mem) \n",
        "                    grads = tape.gradient(total_loss, self.client.trainable_weights)\n",
        "                    # ATTENTION: use global optimizer to update global network with the gradients\n",
        "                    self.opt.apply_gradients(zip(grads, self.server.trainable_weights))\n",
        "\n",
        "                    # ATTENTION: fetch global parameters to local agent\n",
        "                    self.client.set_weights(self.server.get_weights())\n",
        "                    mem.clear() # clear memory of this episode \n",
        "                    # save returns\n",
        "                    self.result_queue.put(ep_reward)\n",
        "                    # print(self.worker_idx, ep_reward)\n",
        "                    break\n",
        "        self.result_queue.put(None) # finish worker thread\n",
        "\n",
        "    def compute_loss(self,\n",
        "                     done,\n",
        "                     new_state,\n",
        "                     memory,\n",
        "                     gamma=0.99):\n",
        "        if done:\n",
        "            reward_sum = 0. # terminal, v(done)=0\n",
        "        else:\n",
        "            reward_sum = self.client(tf.constant(new_state[None, :],\n",
        "                                     dtype=tf.float32))[-1].numpy()[0]\n",
        "        # rewards-to-go along the trajectory\n",
        "        discounted_rewards = []\n",
        "        for reward in memory.rewards[::-1]:  # reverse buffer r\n",
        "            reward_sum = reward + gamma * reward_sum\n",
        "            discounted_rewards.append(reward_sum)\n",
        "        discounted_rewards.reverse()\n",
        "        # state ==> Pi(a|s) and v(s) for the policy\n",
        "        logits, values = self.client(tf.constant(np.vstack(memory.states), dtype=tf.float32))\n",
        "        # advantage = R() - v(s)\n",
        "        advantage = tf.constant(np.array(discounted_rewards)[:, None], dtype=tf.float32) - values\n",
        "        # Critic: v(s) close to R(), or minimize advantage\n",
        "        value_loss = advantage ** 2\n",
        "        # Calculate policy loss\n",
        "        policy = tf.nn.softmax(logits)       # logits of prob(a|s)\n",
        "        policy_loss = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=memory.actions, logits=logits)\n",
        "        # stop v net when calculating policy net\n",
        "        policy_loss = policy_loss * tf.stop_gradient(advantage)\n",
        "        # Entropy Bonus\n",
        "        entropy = tf.nn.softmax_cross_entropy_with_logits(labels=policy, logits=logits)\n",
        "        policy_loss = policy_loss - 0.01 * entropy\n",
        "        # total_loss = value loss + policy loss\n",
        "        total_loss = tf.reduce_mean((0.5 * value_loss + policy_loss))\n",
        "        return total_loss"
      ],
      "execution_count": 87,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "xKptU0h8HnFM",
        "colab_type": "code",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 68
        },
        "outputId": "767fcf0b-77d8-4bee-8494-406697980ad6"
      },
      "source": [
        "opt = keras.optimizers.Adam(1e-3)\n",
        "server = ActorCritic(4, 2)\n",
        "server(tf.random.normal((2, 4)))\n",
        "\n",
        "# train\n",
        "res_queue = Queue()\n",
        "workers = [Worker(server, opt, res_queue, i) for i in range(multiprocessing.cpu_count())]\n",
        "\n",
        "for i, worker in enumerate(workers):\n",
        "  print(\"Starting worker {}\".format(i))\n",
        "  worker.start()\n",
        "\n",
        "returns = []      #total returns\n",
        "while True:\n",
        "    reward = res_queue.get()\n",
        "    if reward is not None:\n",
        "        returns.append(reward)\n",
        "    else: # end\n",
        "        break\n",
        "\n",
        "[w.join() for w in workers]    # wait for thread join"
      ],
      "execution_count": 88,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Starting worker 0\n",
            "Starting worker 1\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "[None, None]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 88
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "NSz4Nd4iERFR",
        "colab_type": "code",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 279
        },
        "outputId": "ea2cb755-30ba-4115-f32f-7129aaced7aa"
      },
      "source": [
        "plt.plot(np.arange(len(returns)), returns)\n",
        "plt.plot(np.arange(len(returns)), returns, 's')\n",
        "plt.xlabel('epoch')\n",
        "plt.ylabel('total return')\n",
        "plt.show()"
      ],
      "execution_count": 89,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": [],
            "needs_background": "light"
          }
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "_jX5SdAmucMG",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": null,
      "outputs": []
    }
  ]
}